#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <limits>
#include <string>
#include <vector>
using namespace std;



// Macro to loop until good input
#define READ_VAR(prompt, var, error) \
	cout << prompt << " "; \
	while (!(cin >> var)) { \
		cout << error << endl; \
		cin.clear(); \
		cin.ignore(numeric_limits<streamsize>::max(), '\n'); \
		cout << prompt << " "; \
	} \
	cin.ignore(numeric_limits<streamsize>::max(), '\n');



int main(int argc, char * argv[]) {
	ofstream outputFile;
	long seed;
	string processName, finished;
	unsigned executionTime, blockingPeriod, blockingLength, priority, deadline, staticOffset, randomOffset, quantity, issueCycle;
	vector <string> names;
	vector < pair <unsigned, unsigned> > issuePeriods;
	vector <unsigned> quantities;

	// Check that the correct number of command-line arguments were made
	if (argc != 3) {
		fprintf(stderr, "usage: %s seed outputfile\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	// Parse the seed argument
	if (sscanf(argv[1], "%ld", &seed) != 1) {
		fprintf(stderr, "seed must be an integer\n");
		exit(EXIT_FAILURE);
	}

	// Open the outputfile argument
	outputFile.open(argv[2]);
	if (!(outputFile.is_open())) {
		perror(argv[2]);
		exit(EXIT_FAILURE);
	}

	// Output header for definition section
	outputFile << "# Name, Execution Time, Blocking Period, Blocking Length, Priority, Deadline" << endl;

	while (true) {
		// Read in definitions
		READ_VAR("Process Name:", processName, "Error -- must be a string");
		READ_VAR("Execution Time:", executionTime, "Error -- must be unsigned integer");
		READ_VAR("Blocking Period:", blockingPeriod, "Error -- must be unsigned integer");
		READ_VAR("Blocking Length:", blockingLength, "Error -- must be unsigned integer");
		READ_VAR("Priority:", priority, "Error -- must be unsigned integer");
		READ_VAR("Deadline:", deadline, "Error -- must be unsigned integer");
		READ_VAR("Static Issue Period Offset:", staticOffset, "Error -- must be unsigned integer");
		READ_VAR("Random Issue Period Offset:", randomOffset, "Error -- must be unsigned integer");
		READ_VAR("Quantity:", quantity, "Error -- must be unsigned integer");

		// Output definition line
		outputFile << processName << " " << executionTime << " " << blockingPeriod << " ";
		outputFile << blockingLength << " " << priority << " " << deadline << endl;
		
		// Save information for issue lines
		names.push_back(processName);
		issuePeriods.push_back(make_pair(staticOffset, randomOffset + 1));
		quantities.push_back(quantity);

		// Check if finished
		while (true) {
			READ_VAR("Finished?:", finished, "Error -- must be a string");
			if ((finished == "yes") || (finished == "no"))
				break;
			cout << "Error -- must be yes/no" << endl;
		}
		if (finished == "yes") {
			break;
		}
	}

	// Output delimiter and header for issue section 
	outputFile << endl << "BEGIN_ISSUE" << endl;
	outputFile << endl << "# Issue Time, Name" << endl;

	// Output issue lines
	srand48(seed);
	for (int i = 0; i < names.size(); ++i) {
		staticOffset = issuePeriods[i].first;
		randomOffset = issuePeriods[i].second;
		for (int j = 0; j < quantities[i]; ++j) {
			issueCycle = (j * staticOffset) + (lrand48() % randomOffset);
			outputFile << issueCycle << " " << names[i] << endl;
		}
		outputFile << endl;
	}

	return 0;
}
